#include <fstream>
#include <sstream>
#include "igslib_iserial_manager.h"
#include "igslib_iexternal_board.h"
#include "igslib_iutil.h"

using namespace igslib;

class firmware_tool
{
    ISerialManager* serial_mgr;
    IUart* uart;
    IExternalBoardManager* exb_mgr;
    IExternalBoard* exb;
    std::string source_path;
    public:
        firmware_tool()
        {
            serial_mgr = GetSerialManagerInstance();
            uart = serial_mgr->NewM01Uart();
            IUart::DeviceNumber dn = IUart::ttyS3;
            uart->SetBaudRate(115200);
            bool odr = uart->Open(dn); // open device result
            if (odr == false)
            {
                std::stringstream ss;
                ss << "Open serial port " << dn << " failed.";
                throw_igslib_exception(ss.str());
            }
			
            exb_mgr = GetExternalBoardManagerInstance();
            exb = exb_mgr->New_MH_MCU();
            exb->SetUART(uart);
        }
        std::string get_version()
        {
            std::string rtn(exb->GetVersion());
            return rtn;
        }
        void load(std::string& source_path)
        {
            std::ifstream fp;
            fp.open(source_path, std::ios::in | std::ios::binary | std::ios::ate );		
            if(!fp)		
            {
                std::stringstream ss;
                ss << "open '" << source_path << "' fail.";
                throw_igslib_exception(ss.str());			
            }

            // get length of file & valid data length:
            fp.seekg (0, fp.end);  //offset:0  start pos: file end
            int flen = fp.tellg(); //locate pos
            fp.seekg (0);

            char* buffer= (char*)malloc(flen); 	
            fp.read(buffer,flen);
            exb->ImportRawData(buffer,flen);

            delete(buffer);			
            fp.close();
        }
        void upgrade()
        {
            exb->Upgrade();
        }
};

static void show_usage()
{
    std::cout << std::endl;
    std::cout << "IGS mobile platform firmware upgrade tool." << std::endl;
    std::cout << "==========================================" << std::endl;
    std::cout << std::endl;
    std::cout << "Syntax:" << std::endl << std::endl;
    std::cout << "    fwtool [operation] [source_path]" << std::endl;
    std::cout << std::endl;
    std::cout << "Description:" << std::endl << std::endl;
    std::cout << "    [operation]: Following operations are available:" << std::endl;
    std::cout << "        read: Get current firmware version on MCU." << std::endl;
    std::cout << "        upgrade: Program [source_path] binary to MCU's firmware." << std::endl;
    std::cout << "    [source_path]: Binary file of firmware." << std::endl;
    std::cout << std::endl;
    std::cout << "Maintainer:" << std::endl << std::endl;
    std::cout << "    <naivechou@igs.com.tw>,#2528" << std::endl;
    std::cout << "    <naive231@gmail.com>" << std::endl;
    std::cout << std::endl;
}
int main(int argc,char** argv)
{
    firmware_tool fwt;   
    if (argc == 1)
    {
        show_usage();
    }
    else if (argc == 2)
    {
        char* operation = argv[1];
        if (strcmp(operation,"read")==0)
        {
            std::cout << fwt.get_version() << std::endl;
        }
        else
        {
            show_usage();
        }
    }
    else if (argc == 3)
    {
        char* operation = argv[1];
        std::string source_path(argv[2]);
        if (strcmp(operation,"upgrade")==0)
        {
            fwt.load(source_path);
            std::cout << "Programming '" << source_path << "' to MCU..." << std::flush;
            fwt.upgrade();
            std::cout << "finish." << std::endl;

            std::cout << "Now version is '" << fwt.get_version() << "'." << std::endl;
        }
        else if (strcmp(operation,"read")==0)
        {
            std::cout << fwt.get_version() << std::endl;
        }
        else
        {
            show_usage();
        }
    }
}
